package com.frp.lib.message;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by hujianjun on 11/22 0022.
 */
// Message wraps socket packages for communicating between frpc and frps.
public class Message {

    public static Map<Byte, Class<? extends Message>> TypeMap = new HashMap<Byte, Class<? extends Message>>();
    public static Map<Class<? extends Message>, Byte> TypeStringMap = new HashMap<Class<? extends Message>, Byte>();

    static {
//        const (
//        TypeLogin             = 'o'
//        TypeLoginResp         = '1'
//        TypeNewProxy          = 'p'
//        TypeNewProxyResp      = '2'
//        TypeCloseProxy        = 'c'
//        TypeNewWorkConn       = 'w'
//        TypeReqWorkConn       = 'r'
//        TypeStartWorkConn     = 's'
//        TypeNewVistorConn     = 'v'
//        TypeNewVistorConnResp = '3'
//        TypePing              = 'h'
//        TypePong              = '4'
//        TypeUdpPacket         = 'u'
//        )
        TypeMap.put((byte)'o', Login.class);
        TypeMap.put((byte)'1', LoginResp.class);
        TypeMap.put((byte)'p', NewProxy.class);
        TypeMap.put((byte)'2', NewProxyResp.class);
        TypeMap.put((byte)'c', CloseProxy.class);
        TypeMap.put((byte)'w', NewWorkConn.class);
        TypeMap.put((byte)'r', ReqWorkConn.class);
        TypeMap.put((byte)'s', StartWorkConn.class);
        TypeMap.put((byte)'v', NewVistorConn.class);
        TypeMap.put((byte)'3', NewVistorConnResp.class);
        TypeMap.put((byte)'h', Ping.class);
        TypeMap.put((byte)'4', Pong.class);
        TypeMap.put((byte)'u', UdpPackage.class);

        for(Byte type : TypeMap.keySet()) {
            Class<? extends Message> clazz = TypeMap.get(type);
            TypeStringMap.put(clazz, type);
        }
    }

    // When frpc start, client send this message to login to server.
    public static class Login extends Message {
        private String version;
        private String hostname;
        private String os;
        private String arch;
        private String user;
        private String privilege_key;
        private long timestamp;
        private String run_id;
        private int pool_count;

        public String getVersion() {
            return version;
        }

        public void setVersion(String version) {
            this.version = version;
        }

        public String getHostname() {
            return hostname;
        }

        public void setHostname(String hostname) {
            this.hostname = hostname;
        }

        public String getOs() {
            return os;
        }

        public void setOs(String os) {
            this.os = os;
        }

        public String getArch() {
            return arch;
        }

        public void setArch(String arch) {
            this.arch = arch;
        }

        public String getUser() {
            return user;
        }

        public void setUser(String user) {
            this.user = user;
        }

        public String getPrivilege_key() {
            return privilege_key;
        }

        public void setPrivilege_key(String privilege_key) {
            this.privilege_key = privilege_key;
        }

        public long getTimestamp() {
            return timestamp;
        }

        public void setTimestamp(long timestamp) {
            this.timestamp = timestamp;
        }

        public String getRun_id() {
            return run_id;
        }

        public void setRun_id(String run_id) {
            this.run_id = run_id;
        }

        public int getPool_count() {
            return pool_count;
        }

        public void setPool_count(int pool_count) {
            this.pool_count = pool_count;
        }

        @Override
        public String toString() {
            return "Login{" +
                    "version='" + version + '\'' +
                    ", hostname='" + hostname + '\'' +
                    ", os='" + os + '\'' +
                    ", arch='" + arch + '\'' +
                    ", user='" + user + '\'' +
                    ", privilege_key='" + privilege_key + '\'' +
                    ", timestamp=" + timestamp +
                    ", run_id='" + run_id + '\'' +
                    ", pool_count=" + pool_count +
                    "} " + super.toString();
        }
    }

    public static class LoginResp extends Message {
        private String version;
        private String run_id;
        private String error;

        public String getVersion() {
            return version;
        }

        public void setVersion(String version) {
            this.version = version;
        }

        public String getRun_id() {
            return run_id;
        }

        public void setRun_id(String run_id) {
            this.run_id = run_id;
        }

        public String getError() {
            return error;
        }

        public void setError(String error) {
            this.error = error;
        }

        @Override
        public String toString() {
            return "LoginResp{" +
                    "version='" + version + '\'' +
                    ", run_id='" + run_id + '\'' +
                    ", error='" + error + '\'' +
                    "} " + super.toString();
        }
    }

    // When frpc login success, send this message to frps for running a new proxy.
    public static class NewProxy extends Message {
        private String proxy_name;
        private String proxy_type;
        private boolean use_encryption;
        private boolean use_compression;
        //tcp and udp only
        private long remote_port;
        //http and https only
        private String[] custom_domains;
        private String subdomain;
        private String[] locations;
        private String host_header_rewrite;
        private String http_user;
        private String http_pwd;
        //stcp
        private String sk;

        public String getProxy_name() {
            return proxy_name;
        }

        public void setProxy_name(String proxy_name) {
            this.proxy_name = proxy_name;
        }

        public String getProxy_type() {
            return proxy_type;
        }

        public void setProxy_type(String proxy_type) {
            this.proxy_type = proxy_type;
        }

        public boolean isUse_encryption() {
            return use_encryption;
        }

        public void setUse_encryption(boolean use_encryption) {
            this.use_encryption = use_encryption;
        }

        public boolean isUse_compression() {
            return use_compression;
        }

        public void setUse_compression(boolean use_compression) {
            this.use_compression = use_compression;
        }

        public long getRemote_port() {
            return remote_port;
        }

        public void setRemote_port(long remote_port) {
            this.remote_port = remote_port;
        }

        public String[] getCustom_domains() {
            return custom_domains;
        }

        public void setCustom_domains(String[] custom_domains) {
            this.custom_domains = custom_domains;
        }

        public String getSubdomain() {
            return subdomain;
        }

        public void setSubdomain(String subdomain) {
            this.subdomain = subdomain;
        }

        public String[] getLocations() {
            return locations;
        }

        public void setLocations(String[] locations) {
            this.locations = locations;
        }

        public String getHost_header_rewrite() {
            return host_header_rewrite;
        }

        public void setHost_header_rewrite(String host_header_rewrite) {
            this.host_header_rewrite = host_header_rewrite;
        }

        public String getHttp_user() {
            return http_user;
        }

        public void setHttp_user(String http_user) {
            this.http_user = http_user;
        }

        public String getHttp_pwd() {
            return http_pwd;
        }

        public void setHttp_pwd(String http_pwd) {
            this.http_pwd = http_pwd;
        }

        public String getSk() {
            return sk;
        }

        public void setSk(String sk) {
            this.sk = sk;
        }

        @Override
        public String toString() {
            return "NewProxy{" +
                    "name='" + proxy_name + '\'' +
                    ", type='" + proxy_type + '\'' +
                    ", use_encryption=" + use_encryption +
                    ", use_compression=" + use_compression +
                    ", remote_port=" + remote_port +
                    ", custom_domains=" + Arrays.toString(custom_domains) +
                    ", subdomain='" + subdomain + '\'' +
                    ", locations=" + Arrays.toString(locations) +
                    ", host_header_rewrite='" + host_header_rewrite + '\'' +
                    ", http_user='" + http_user + '\'' +
                    ", http_pwd='" + http_pwd + '\'' +
                    ", sk='" + sk + '\'' +
                    "} " + super.toString();
        }
    }

    public static class NewProxyResp extends Message {
        private String proxy_name;
        private String error;

        public String getProxy_name() {
            return proxy_name;
        }

        public void setProxy_name(String proxy_name) {
            this.proxy_name = proxy_name;
        }

        public String getError() {
            return error;
        }

        public void setError(String error) {
            this.error = error;
        }

        @Override
        public String toString() {
            return "NewProxyResp{" +
                    "name='" + proxy_name + '\'' +
                    ", error='" + error + '\'' +
                    "} " + super.toString();
        }
    }

    public static class CloseProxy extends Message {
        private String proxy_name;

        public String getProxy_name() {
            return proxy_name;
        }

        public void setProxy_name(String proxy_name) {
            this.proxy_name = proxy_name;
        }

        @Override
        public String toString() {
            return "CloseProxy{" +
                    "name='" + proxy_name + '\'' +
                    "} " + super.toString();
        }
    }

    public static class NewWorkConn extends Message {
        private String run_id;

        public String getRun_id() {
            return run_id;
        }

        public void setRun_id(String run_id) {
            this.run_id = run_id;
        }

        @Override
        public String toString() {
            return "NewWorkConn{" +
                    "run_id='" + run_id + '\'' +
                    "} " + super.toString();
        }
    }

    public static class ReqWorkConn extends Message {

    }

    public static class StartWorkConn extends Message {
        private String proxy_name;

        public String getProxy_name() {
            return proxy_name;
        }

        public void setProxy_name(String proxy_name) {
            this.proxy_name = proxy_name;
        }

        @Override
        public String toString() {
            return "StartWorkConn{" +
                    "name='" + proxy_name + '\'' +
                    "} " + super.toString();
        }
    }

    public static class NewVistorConn extends Message {
        private String proxy_name;
        private String sign_key;
        private long timestamp;
        private boolean use_encryption;
        private boolean use_compression;

        public String getProxy_name() {
            return proxy_name;
        }

        public void setProxy_name(String proxy_name) {
            this.proxy_name = proxy_name;
        }

        public String getSign_key() {
            return sign_key;
        }

        public void setSign_key(String sign_key) {
            this.sign_key = sign_key;
        }

        public long getTimestamp() {
            return timestamp;
        }

        public void setTimestamp(long timestamp) {
            this.timestamp = timestamp;
        }

        public boolean isUse_encryption() {
            return use_encryption;
        }

        public void setUse_encryption(boolean use_encryption) {
            this.use_encryption = use_encryption;
        }

        public boolean isUse_compression() {
            return use_compression;
        }

        public void setUse_compression(boolean use_compression) {
            this.use_compression = use_compression;
        }

        @Override
        public String toString() {
            return "NewVistorConn{" +
                    "name='" + proxy_name + '\'' +
                    ", sign_key='" + sign_key + '\'' +
                    ", timestamp=" + timestamp +
                    ", use_encryption=" + use_encryption +
                    ", use_compression=" + use_compression +
                    "} " + super.toString();
        }
    }

    public static class NewVistorConnResp extends Message {
        private String proxy_name;
        private String error;

        public String getProxy_name() {
            return proxy_name;
        }

        public void setProxy_name(String proxy_name) {
            this.proxy_name = proxy_name;
        }

        public String getError() {
            return error;
        }

        public void setError(String error) {
            this.error = error;
        }

        @Override
        public String toString() {
            return "NewVistorConnResp{" +
                    "name='" + proxy_name + '\'' +
                    ", error='" + error + '\'' +
                    "} " + super.toString();
        }
    }

    public static class Ping extends Message {
        @Override
        public String toString() {
            return "Ping{} " + super.toString();
        }
    }

    public static class Pong extends Message {
        @Override
        public String toString() {
            return "Pong{} " + super.toString();
        }
    }

    public static class UdpPackage extends Message {
        //todo will do it
        private String c;   //Content;
        private String l;   //LocalAddr  *net.UDPAddr `json:"l"`
        private String r;   //RemoteAddr *net.UDPAddr `json:"r"`

    }

}
